<template>
  <div
    ref="wrapRef"
    :class="[
      'basic-form',
      `basic-form-bg-${getProps.theme}`,
      getProps.showActionButtonGroup
        ? showMoreFilter
          ? 'open-height'
          : 'stow-height'
        : '',
    ]"
  >
    <div class="from-container">
      <Form ref="formElRef" :model="formData" v-bind="getProps" @submit.native.prevent @keyup.native.enter="handleEnterSearch">
        <Row :gutter="16" type="flex" style="flex-wrap: wrap;">
          <FormItem
            v-for="item in getProps.schemas"
            :key="item.field"
            v-bind="{
            ...item,
            colProps: item.colProps || getProps.colProps,
            labelWidth: item.labelWidth || getProps.labelWidth,
            formData,
            formItemMb: getProps.formItemMb,
            isReset,
            }"
            :value="formData[item.prop]"
            @change="handleChange"
            @enter="handleEnterSearch"
          >
            <template v-for="slot in Object.keys(slots)" #[slot]="data">
              <slot :name="slot" v-bind="data || {}" />
            </template>
          </FormItem>
        </Row>
      </Form>
    </div>
    <template v-if="getProps.showActionButtonGroup">
      <FormAction v-bind="getProps" @moreFilter="handleMoreFilter" @submit="handleSumit" @reset="handleReset">
        <template v-for="slot in Object.keys(slots)" #[slot]="data">
          <slot :name="slot" v-bind="data || {}" />
        </template>
      </FormAction>
    </template>
  </div>
</template>

<script setup name="basic-form">
import { ref, computed, unref, watch, useSlots } from 'vue'
import { Form, Row } from 'element-ui'
import FormItem from './components/FormItem.vue'
import FormAction from './components/FormAction.vue'

import { basicProps } from './props'

const slots = useSlots()

const props = defineProps(basicProps)
const emit = defineEmits(['change', 'register', 'submit', 'reset'])
const wrapRef = ref(null)
const formElRef = ref(null)
const formData = ref({})
const copySchemas = ref('')
const showMoreFilter = ref(false)
const isReset = ref(false)

const getProps = computed(() => ({ ...props, ...unref(wrapRef) }))

watch(
  () => unref(getProps).model,
  (model) => setFieldValues(model),
  { immediate: true, deep: true }
)

watch(
  () => unref(getProps).schemas,
  (value) => {
    let result = value
    if (unref(getProps).isFlex) {
      result = setFormItemLayout(value)
    }
    formData.value = getRuleForm(result)
    copySchemas.value = JSON.stringify(result)
  },
  {
    immediate: true
  }
)

const formAction = {
  setProps,
  validate,
  validateField,
  clearValidate,
  reset,
  getFieldValues,
  setFieldValues,
  updateSchema,
  insetSchema,
  removeSchemaByFiled,
  resetSchemas,
  updateSchemaByIndex,
  updateBtnStatus
}

emit('register', formAction)

function setProps(props) {
  wrapRef.value = { ...unref(wrapRef), ...props }
}

function updateBtnStatus(field, value) {
  unref(wrapRef)[field] = value
}

function validate() {
  return formElRef.value.validate()
}

function validateField(prop) {
  return unref(formElRef).validateField(prop)
}

function clearValidate() {
  formElRef.value.clearValidate()
}

function reset() {
  isReset.value = true
  formData.value = getRuleForm(unref(getProps).schemas)
  formElRef.value.resetFields()
}

function getFieldValues() {
  return unref(formData)
}

function setFieldValues(data) {
  formData.value = { ...unref(formData), ...data }
  return unref(formData)
}

// 根据索引值更新表单项配置
function updateSchemaByIndex(index, schema) {
  if (index < 0) return console.error('index 必须大于0')
  if (!schema && Object.keys(schema)) {
    console.error('schema 不能为空')
  }
  unref(getProps).schemas[index] = schema
  setProps({ ...unref(getProps), schema })
}

function updateSchema(schema, field = 'prop') {
  if (!schema || Object.keys(schema).length === 0) return
  const schemas = unref(getProps).schemas
  const index = schemas.findIndex((item) => item[field] === schema[field])
  if (index !== -1) {
    schemas[index] = schema
  }
  if (schema.defaultValue) {
    setFieldValues({ [schema.prop]: schema.defaultValue })
  }
  setProps({ ...unref(getProps), schemas })
}

function insetSchema(prop, schema) {
  if (!prop || !schema || Object.keys(schema).length === 0) return
  const schemas = unref(getProps).schemas
  const eIndex = schemas.findIndex((item) => item.prop === schema.prop)
  if (eIndex !== -1) {
    // console.error('已存在该表单项')
    // schemas.splice(eIndex, 1)
    // setProps({ ...unref(getProps), schemas })
    return
  }
  const index = schemas.findIndex((item) => item.prop === prop)
  if (index !== -1) {
    schemas.splice(index, 0, schema)
    setFieldValues({ [schema.prop]: schema.defaultValue ?? '' })
    setProps({ ...unref(getProps), schemas })
  }
}

function removeSchemaByFiled(field) {
  if (!field) return
  const schemas = unref(getProps).schemas
  const index = schemas.findIndex((item) => item.prop === field)
  if (index !== -1) {
    schemas.splice(index, 1)
  }
  setProps({ ...unref(getProps), schemas })
}

function resetSchemas() {
  const schemas = JSON.parse(unref(copySchemas))
  setProps({ ...unref(getProps), schemas })
}

function getRuleForm(schemas, isReset = false) {
  const result = {}
  schemas.forEach((item) => {
    if (item.component !== 'Divider') {
      result[item.prop] = isReset ? '' : item.defaultValue ?? ''
    }
  })
  return result
}

function handleChange(e) {
  formData.value[e.prop] = e.value
  emit('change', e)
}

function handleEnterSearch() {
  unref(getProps).isEnterSearch && handleSumit()
}

function handleMoreFilter(e) {
  showMoreFilter.value = e
}

async function handleSumit() {
  const res = await validate()
  res && emit('submit', getFieldValues())
}

function handleReset() {
  reset()
  emit('reset')
}

function setLayout() {
  return {
    // 页面有侧边栏时
    xs: {
      colProps: { span: 12, xs: 24, sm: 24, md: 24, lg: 12, xl: 8 }
    },
    // 页面有侧边栏 没有日期组件时
    sm: {
      colProps: { span: 12, xs: 24, sm: 24, md: 24, lg: 12, xl: 8 }
    },
    default: {
      colProps: { span: 8, xs: 24, md: 12, lg: 8, xl: 6 }
    }
  }
}

function setFormItemLayout(schemas) {
  const layout = setLayout()
  return schemas.map((s) => {
    if (s.colProps && Object.keys(s.colProps).length) return s
    const result = layout[unref(getProps).formSize]
    s.colProps = result.colProps
    return s
  })
}
</script>

<style lang="scss">
@import "@/styles/bas.scss";

.basic-form {
  overflow: hidden;
  display: flex;
  height: 100%;
  padding: 16px 16px 0 0;
  background-color: $form-bg;

  .from-container {
    flex: 1;
    overflow: hidden auto;
  }
}

.basic-form-bg-white {
  background-color: white;
}

.stow-height {
  height: 64px;

  .from-container {
    overflow: hidden;
  }
}

.open-height {
  height: auto;

  .from-container {
    overflow: hidden;
  }
}

.el-form {
  overflow: hidden auto;
}
</style>
